const jwt = require('jsonwebtoken')
const jwtKoa = require('koa-jwt'); // 用于路由权限控制
const { JWT_SECRET } = require('@/config/config.default')
const { TokenExpiredError, JsonWebTokenError } = require('@/constant/errType')
//引入log4js帮助js
const logUtil = require('@/util/logUtil')

// 一些中间件
module.exports = (app) => {
    /* 401未授权返回自定义的数据格式 */
    app.use(async function (ctx, next) {     //如果返回的是401未授权status
        try {
            await next()
        }
        catch (err) {
            if (401 == err.status) {
                switch (err.name) {
                    case 'TokenExpiredError':
                        console.error('token已过期', err)
                        return ctx.app.emit('error', TokenExpiredError, ctx)
                    case 'UnauthorizedError':
                        console.error('无效的token', err)
                        return ctx.app.emit('error', JsonWebTokenError, ctx)
                    default:
                        ctx.status = 401
                        return ctx.app.emit('error', JsonWebTokenError, ctx)
                }
            } else {
                throw err
            }
        }
    })
    /* 路由权限控制 */
    app.use(jwtKoa({ secret: JWT_SECRET }).unless({
        // 设置login、registe接口，可以不需要认证访问   
        path: [
            /^\/users\/login/,
            /^\/users\/registe/,
            /^\/article/,
            /^\/school\/menuList/,
            // /^((?!\/users).)*$/, // 设置接口外的其它资源，可以不需要认证访问   
        ]
    }))

    app.use(async function (ctx, next) {     // 如果是携带了token的请求,解析这个token并 放置在ctx.user下
        try {
            const authorization = ctx.header.authorization  // 获取jwt
            if (authorization) {
                let token = authorization.split(' ')[1]
                if (token && token.length > 10) { //客户端传过来的Authorization: Bearer null会被解析成token为"null",简单点用长度来过滤
                    let payload = await jwt.verify(token, JWT_SECRET)  // 解密，获取payload
                    ctx.user = payload
                }
            }
            await next()
        }
        catch (err) {    //这个中间件不做任何路由拦截处理，因为koa-jwt已经做了, 这个中间件的作用是，如果token能够解析正确，就把它解析成登录用户对象并赋值给 ctx.user
            throw err
        }
    })
    // 日志
    app.use(async (ctx, next) => {       // 写日志的中间件, 此中间件应放在业务中间件的前面    
        const start = new Date()         //响应开始时间    
        var ms                           //响应间隔时间
        try {        
            await next()                 //开始进入到下一个中间件
            ms = new Date() - start
            //记录响应日志
            logUtil.logResponse(ctx, ms)
        } catch (error) {
            ms = new Date() - start
            //记录异常日志
            logUtil.logError(ctx, error, ms)
        }
    })
}